#pragma once
#include "Log.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include "InetArr.hpp"
#include <functional>

namespace TcpServerMoudle
{
    using namespace LogModule;
    const int gdefaultport = 8080;
    using handle_t = std::function<std::string(const std::string &)>;
    class TcpServer
    {
    public:
        TcpServer(handle_t handle = defaultHandle, int port = gdefaultport)
            : _listenSockfd(-1),
              _inet(port),
              _isrunning(false),
              _handle(handle)
        {
        }

        ~TcpServer()
        {
            if (!_isrunning)
                return;

            _isrunning = false;
            ::close(_listenSockfd);
            LOG(LogLevel::DEBUG) << "Resource recovery successful";
        }

        void InitServer()
        {
            if (_isrunning)
                return;
            // 创建socket bind listen
            _listenSockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listenSockfd == -1)
            {
                LOG(LogLevel::ERROR) << "socket failed";
                DIE(SOCKET_ERROR);
            }

            LOG(LogLevel::DEBUG) << "socket success";

            int n = bind(_listenSockfd, _inet.NetAddr(), _inet.NetAddrLen());
            if (n == -1)
            {
                LOG(LogLevel::ERROR) << "bind failed";
                DIE(BIND_ERROR);
            }
            LOG(LogLevel::DEBUG) << "bind success";

            n = listen(_listenSockfd, 8);
            if (n == -1)
            {
                LOG(LogLevel::ERROR) << "listen failed";
                DIE(LISTEN_ERROR);
            }
            LOG(LogLevel::DEBUG) << "listen success";
        }

        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true;

            while (true)
            {
                struct sockaddr_in peer;
                socklen_t peerLen = sizeof(peer);
                int sockfd = accept(_listenSockfd, CONV(&peer), &peerLen);
                if (sockfd == -1)
                {
                    LOG(LogLevel::ERROR) << "accept failed";
                    continue;
                }

                Handle(sockfd, InetAddr(peer));
            }
        }

    private:
        void Handle(int sockfd, InetAddr inet)
        {
            char buffer[1024];
            while (true)
            {
                int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
                if (n <= 0)
                {
                    LOG(LogLevel::ERROR) << "recv failed";
                    DIE(RECV_ERROR);
                }
                buffer[n] = 0;
                std::string result = _handle(buffer);

                LOG(LogLevel::DEBUG) << "from " + inet.Addr() + ":" << buffer;

                n = send(sockfd, result.c_str(), result.size(), 0);
                if (n == -1)
                {
                    LOG(LogLevel::ERROR) << "send failed";
                    continue;
                }
            }
        }

        static std::string defaultHandle(const std::string &info)
        {
            std::string reslut = "echo#" + info;
            return reslut;
        }

    private:
        int _listenSockfd;
        InetAddr _inet;
        bool _isrunning;
        handle_t _handle;
    };

}